package com.mf.service.impl.purchase;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mf.bo.DateScopedBo;
import com.mf.config.BasicKey;
import com.mf.entity.CodeHistory;
import com.mf.entity.PurchaseRecord;
import com.mf.service.ICodeHistoryService;
import com.mf.service.IPurchaseRecordService;
import com.mf.service.purchase.PurchaseCalculation5;
import com.mf.utils.StockGatherUtils;
import com.mf.vo.CapitalVo;
import com.mf.vo.SingleHoldVo;
import com.mf.vo.StockGatherVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: lmf
 * @Create: 2024/9/15 15:03
 * Description:  买入计算逻辑1
 */
@Slf4j
@Service
public class PurchaseCalculationImpl5 implements PurchaseCalculation5 {

    @Resource
    private IPurchaseRecordService purchaseRecordService;

    @Resource
    private ICodeHistoryService codeHistoryService;


    /**
     * 根据可买入日期进行分配
     */
    @Override
    public List<CapitalVo> calculateByBuyDate(int copies) {


        final LambdaQueryWrapper<PurchaseRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByAsc(PurchaseRecord::getBuyDate);

        // 所有的购买记录
        final List<PurchaseRecord> list = purchaseRecordService.list(wrapper);
        // 按照 getBuyDate 进行分组，并确保分组后的日期是有序的
        Map<String, List<PurchaseRecord>> groupedAndSorted = list.stream().collect(Collectors.groupingBy(PurchaseRecord::getBuyDate));
        // 将分组后的 Map 转换为有序的 Map
        SortedMap<String, List<PurchaseRecord>> sortedGrouped = new TreeMap<>(groupedAndSorted);

        final List<CapitalVo> capitalVoList = calculateByShare(copies);
        for (CapitalVo capitalVo : capitalVoList) {
            // 遍历所有可买入日期
            for (Map.Entry<String, List<PurchaseRecord>> stringListEntry : sortedGrouped.entrySet()) {

                if (capitalVo.getCurrentDate() == null) {
                    capitalVo.setCurrentDate(stringListEntry.getKey());
                }

                // 如果当前日期小于基准日期那么跳过
                if (capitalVo.getCurrentDate() != null && isBuyDateOnOrAfter(stringListEntry.getKey(), capitalVo.getCurrentDate())) {
                    continue;
                }

                if (!capitalVo.isHolding()) {
                    capitalVo.setHolding(true);
                    final HashMap<String, Object> hashMap = getBuyCodeList(stringListEntry, 0);
                    if (hashMap == null) {
                        continue;
                    }
                    // 获取买入代码
                    final List<CodeHistory> buyCodeList = (List<CodeHistory>) hashMap.get("dayHistoryList");
                    // 获取当前购买记录
                    final PurchaseRecord purchaseRecord = (PurchaseRecord) hashMap.get("purchaseRecord");


                    if (buyCodeList.size() > BasicKey.MIN_DAY) {
                        final StockGatherVo dayStockGatherVo = StockGatherUtils.getStockGather(buyCodeList);
                        for (int i = BasicKey.MIN_DAY; i < dayStockGatherVo.getDate().length; i++) {
                            // 当前日期 和选入历史买入一致是买入
                            if (dayStockGatherVo.getDate()[i].equals(purchaseRecord.getBuyDate())) {
                                // 卖出的下标
                                final int i1 = calculateBySellPrice(dayStockGatherVo, i);
                                if (i1 != -1) {
                                    setCapitalVo(capitalVo, i1, dayStockGatherVo, i);
                                    break;
                                } else {
                                    log.info("推算完成======================================》");
                                    break;
                                }
                            }
                        }
                    }
                }
            }

        }
        summaryInfo(capitalVoList);
        return capitalVoList;
    }

    /**
     * 获取股票集合最小年第一天日期
     */
    public int getMinYearFirstDay(List<CodeHistory> dayHistoryList, String year) {
        int _year = Integer.parseInt(year.substring(0, 4));
        if (dayHistoryList.get(0).getD().substring(0, 4).equals("" + _year)) {
            _year++;
        }
        for (int i = 0; i < dayHistoryList.size(); i++) {
            if (dayHistoryList.get(i).getD().substring(0, 4).equals(_year + "")) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 汇总信息
     */
    private void summaryInfo(List<CapitalVo> capitalVoList) {
        for (CapitalVo capitalVo : capitalVoList) {
            for (SingleHoldVo singleHoldVo : capitalVo.getSingleHoldVoList()) {
                if (singleHoldVo.getProfit() > 0) {
                    // 记录成功次数
                    capitalVo.setSuccessCount(capitalVo.getSuccessCount() + 1);
                } else {
                    // 记录失败次数
                    capitalVo.setFailCount(capitalVo.getFailCount() + 1);
                }
                // 总收益
                capitalVo.setTotalProfit(capitalVo.getTotalProfit() + singleHoldVo.getProfit());
                // 持有总天数
                capitalVo.setTotalDays(capitalVo.getTotalDays() + singleHoldVo.getDays());
                // 总购买次数
                capitalVo.setTotalBuyCount(capitalVo.getTotalBuyCount() + 1);

            }
            final double amount =
                    capitalVo.getSingleHoldVoList().get(capitalVo.getSingleHoldVoList().size() - 1).getAmount();
            // 持有金额
            capitalVo.setCapital(amount);
        }
    }

    /**
     * 设置单次买入卖出信息
     */
    private void setCapitalVo(CapitalVo capitalVo, int sellIndex, StockGatherVo dayStockGatherVo, int buyIndex) {
        final SingleHoldVo singleHoldVo = new SingleHoldVo();
        // 买入日期
        singleHoldVo.setBuyDate(dayStockGatherVo.getDate()[buyIndex]);
        // 卖出日期
        singleHoldVo.setSellDate(dayStockGatherVo.getDate()[sellIndex]);
        // 买入价格 k[0] 开盘价   k[1] 收盘价  k[2] 最低价  k[3] 最高价1
        singleHoldVo.setBuyPrice(dayStockGatherVo.getK()[buyIndex][0]);
        // 卖出价格
        singleHoldVo.setSellPrice(dayStockGatherVo.getK()[sellIndex][1]);
        // 持有天数
        singleHoldVo.setDays(sellIndex - buyIndex);

        // 盈利盈利百分比
        singleHoldVo.setProfit(calculatePercentageChange(singleHoldVo.getBuyPrice(), singleHoldVo.getSellPrice()));
        // 买入金额
        final double buyAmount = capitalVo.getCapital() + (capitalVo.getCapital() * singleHoldVo.getProfit() / 100);
        singleHoldVo.setAmount(buyAmount);

        capitalVo.setCapital(buyAmount);
        // 持有盈利
        singleHoldVo.setProfitAmount(buyAmount - capitalVo.getCapital());
        // 股票代码
        singleHoldVo.setDm(dayStockGatherVo.getDm());

        List<SingleHoldVo> singleHoldVoList = capitalVo.getSingleHoldVoList();
        if (singleHoldVoList == null) {
            singleHoldVoList = new ArrayList<>();
        }
        singleHoldVoList.add(singleHoldVo);
        capitalVo.setSingleHoldVoList(singleHoldVoList);

        capitalVo.setHolding(false);
        // 更加基准日期
        capitalVo.setCurrentDate(dayStockGatherVo.getDate()[sellIndex + 1]);

    }


    /**
     * 获取购买的代码 (递归调用直到获取)
     */
    private HashMap<String, Object> getBuyCodeList(Map.Entry<String, List<PurchaseRecord>> stringListEntry, int count) {
        // 查询的年数
        final int year = 6;
        final int startYear = year - 2;

        final DateScopedBo dateScopedBo = new DateScopedBo();
        dateScopedBo.setStartDate(LocalDate.now().minusYears(year).toString());
        dateScopedBo.setEndDate(LocalDate.now().toString());


        List<PurchaseRecord> records = stringListEntry.getValue();
        if (count >= records.size()) {
            return null;
        }


        // 在长度范围内随机选取一个索引
        int useIndex = new Random().nextInt(records.size());

        // 获取当前购买记录
        PurchaseRecord purchaseRecord = records.get(useIndex);


        // 获取 CodeHistory 列表
        final List<CodeHistory> dayHistoryList = codeHistoryService.getHistoryList(dateScopedBo, purchaseRecord.getDm(), "dn");

        if (dayHistoryList == null || dayHistoryList.isEmpty()) {
            return null;
        }
        // 最小年份为当前查询天的前4年开始
        final int minYearFirstDay = getMinYearFirstDay(dayHistoryList, LocalDate.now().minusYears(startYear).toString());
        if (minYearFirstDay == -1) {
            return null;
        }
        BasicKey.MIN_DAY = minYearFirstDay;

        if (dayHistoryList.size() > BasicKey.MIN_DAY) {
//            log.info("=============================>当前计算股票:{}", purchaseRecord.getDm());
//            log.info("当前日期:{}", purchaseRecord.getBuyDate());
            final HashMap<String, Object> map = new HashMap<>();
            map.put("dayHistoryList", dayHistoryList);
            map.put("purchaseRecord", purchaseRecord);

            return map;
        } else {
            return getBuyCodeList(stringListEntry, count + 1);
        }
    }

    /**
     * 计算卖出时机
     */
    public int calculateBySellPrice(StockGatherVo stockGatherVo, int buyIndex) {
        // 买入价格
        double buyPrice = stockGatherVo.getK()[buyIndex][0];

        // 记录买入后最高收入价格
        double maxPrice = 0;
        // 卖出下标
        int sellIndex = -1;

        // 计划卖出最低价
        double sellPrice = 0;

        for (int j = buyIndex + 1; j < stockGatherVo.getDate().length - 1; j++) {
            // k[0] 开盘价   k[1] 收盘价  k[2] 最低价  k[3] 最高价1
            maxPrice = stockGatherVo.getK()[j][1];

            if (isFallExceedsThreshold(buyPrice, maxPrice, -10)) {
                System.out.println("现对于买入后最高收盘价跌幅大于10%直接卖出");
                sellIndex = j;
                break;
            }

            // MA5小于MA10  这时记录准备卖出
            if (stockGatherVo.getMa5().get(j) < stockGatherVo.getMa10().get(j) && sellPrice == 0) {
                sellPrice = stockGatherVo.getK()[j][2];
            }

            if (sellPrice != 0) {
                if (stockGatherVo.getK()[j][1] < sellPrice) {
                    sellIndex = j;
                    break;
                }

                // 如果重新MA5大于MA10，则重置卖出价格
                if (stockGatherVo.getMa5().get(j) > stockGatherVo.getMa10().get(j)) {
                    sellPrice = 0;
                }
            }

        }
        return sellIndex;
    }

    /**
     * 判断买入日期是否在当前日期之后
     */
    public static boolean isBuyDateOnOrAfter(String buyDate, String presentDate) {
        final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate bDate = LocalDate.parse(buyDate, DATE_FORMATTER);
        LocalDate currentDate = LocalDate.parse(presentDate, DATE_FORMATTER);
        final boolean before = bDate.isBefore(currentDate);
        return before && !buyDate.equals(presentDate);
    }

    /**
     * 判断A值相对于B值的跌幅是否超过指定的百分比。
     *
     * @param a         A值
     * @param b         B值
     * @param threshold 跌幅阈值百分比（例如：5表示5%）
     * @return 如果A值相对于B值的跌幅超过threshold，则返回true；否则返回false。
     */
    public boolean isFallExceedsThreshold(double a, double b, double threshold) {
        // 防止除以零的情况
        if (b == 0) {
            throw new IllegalArgumentException("B值不能为零");
        }
        // 比较跌幅百分比是否超过阈值
        return calculatePercentageChange(a, b) <= threshold;
    }

    /**
     * 计算A值相对于B值多了或少了百分之多少。
     *
     * @param a A值
     * @param b B值
     * @return 返回一个字符串表示A值相对于B值多了或少了百分之多少
     */
    public double calculatePercentageChange(double a, double b) {
        // 防止除以零的情况
        if (b == 0) {
            throw new IllegalArgumentException("B值不能为零");
        }

        // 计算差值的百分比
        return ((b - a) / b) * 100;
    }

    /**
     * 根据份数，将总金额分为对应份数
     */
    public List<CapitalVo> calculateByShare(int copies) {
        List<CapitalVo> capitalVoList = new ArrayList<>();
        for (int i = 0; i < copies; i++) {
            CapitalVo capitalVo = new CapitalVo();
            // 总买入金额
            double totalBuyAmount = 10000;
            capitalVo.setCapital(totalBuyAmount / copies);
            capitalVoList.add(capitalVo);
        }
        return capitalVoList;
    }
}
